/*
 * dynamic array interface implemented file.
 * 优点是可以通过下标寻址，提高效率
 ****************************************************
 * @author chenxin<chenxin619315@gmail.com>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dynaArrlib.h"

#ifdef DEBUG
 	#define debug_print printf
#else
	#define debug_print
#endif

static int cel_array_init(cel_array_t *array, int opacity);
static void **create_array_blocks(unsigned int __blocks);
static int cel_array_destroy(cel_array_t *array, cel_release_callback_fn_t relfunc);
static void resize_array(cel_array_t *array, unsigned int opacity);

/* create a new cel array with a specified size. */
cel_array_t *new_cel_array_opacity(int opacity)
{
	cel_array_t *ptr = (cel_array_t *)malloc(sizeof(cel_array_t));
	if(ptr == NULL) {
		perror("new_cel_array_opacity malloc");
	}

	if(cel_array_init(ptr, opacity) < 0)
	{
		free(ptr);
	}

	return ptr;
}

/* initialize the specified cel_array_t
 * 0 for success and -1 for failed 
 */
static int cel_array_init(cel_array_t *array, int opacity)
{
	if(opacity < 0)
		return -1;

	array->items = create_array_blocks(opacity);
	if(array->items == NULL)
		return -1;
	
	array->length = opacity;
	array->size = 0;

	return 0;
}

/* create a specified number of prt blocks
 * 返回一个二级指针（指针数组），指针数组元素的个数
 * 为动态数组的大小，对应动态数组的各个元素
 */
static void **create_array_blocks(unsigned int __blocks)
{
	void **items = (void **)calloc(__blocks, sizeof(void *));
	if(items == NULL) {
		perror("create_array_blocks calloc");
	}

	return items;
}

void free_cel_array(cel_array_t **array, cel_release_callback_fn_t relfunc)
{
	if(array == NULL)
		return;

	if(*array != NULL)
	{
		cel_array_destroy(*array, relfunc);
		free(*array);
		*array = NULL;
	}
}

/* destroy the specified cel_array_t
 * 0 for success and -1 for failed
 */
static int cel_array_destroy(cel_array_t *array, cel_release_callback_fn_t relfunc)
{
	//register int i;
	int i;

	if(array != NULL)
	{
		if(relfunc != NULL)
		{
			for(i = 0; i < array->size; i++)
			{
				relfunc(array->items[i]);
			}
		}

		free(array->items);
		array->items = NULL;
	}
	return 0;
}

/* 添加一个元素到数组的尾部,此方法可以扩充size */
void cel_array_add(cel_array_t *array, void *value)
{
	if(array->size >= array->length) {
		resize_array(array, array->size *2 +1);
	}
	array->items[array->size++] = value;
}

static void resize_array(cel_array_t *array, unsigned int opacity)
{
	void **nitems = create_array_blocks(opacity);

	memcpy(nitems, array->items, array->size * sizeof(void *));

	/* free the old items */
	free(array->items);
	array->items = nitems;
	array->length = opacity;
}

/* insert a specified element to at a specified position */
int cel_array_insert(cel_array_t *array, unsigned int idx, void *value)
{
	unsigned int i;

	if(idx >= array->size)
		return -1;
	
	if(array->size >= array->length) {
		resize_array(array, array->size * 2 + 1);
	}

	/* copy the items */
	for(i = array->size; i > idx; i--)
	{
		array->items[i] = array->items[i-1];
	}
	array->items[idx] = value;
	array->size++;

	return 0;
}

/* deletet the element at a specified position 
 * the deleted element will be returned 
 */
void *cel_array_del(cel_array_t *array, unsigned int idx)
{
	unsigned int i;
	void *old;

	if(idx >= array->size)
		return NULL;

	old = array->items[idx];
	
	for(i = idx; i < array->size; i++)
	{
		array->items[i] = array->items[i+1];
	}
	array->size--;

	return old;
}

/* get the element at a specified postion.*/
void *cel_array_get(cel_array_t *array, unsigned int idx)
{
	if(idx >= array->size)
		return NULL;

	return array->items[idx];
}

/* search the object in the array return the index */
int cel_array_get_obj(cel_array_t *array, void *obj, cel_compare_fn_t cfunc)
{
	unsigned int i;

	for(i = 0; i < array->size; i++)
	{
		if(obj == array->items[i] || cfunc(array->items[i], obj) == 0)
		{
			return i;
		}
	}
	return -1;
}

/* replace the element at a specified position 
 * with a new value, and the old element will be return 
 */
void *cel_array_set(cel_array_t *array, unsigned int idx, void *value)
{
	void *old;
	
	if(idx >= array->size)
		return NULL;

	old = array->items[idx];
	array->items[idx] = value;

	return old;
}

